﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Sprout.Core.Security
{
    public partial class AESHelper
    {
        /// <summary>
        /// AES 加密
        /// </summary>
        /// <param name="data">需要加密的数据</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static string Encrypt(string data, string key, CipherMode mode = CipherMode.ECB)
        {
            MemoryStream memoryStream = null;
            CryptoStream cryptoStream = null;
            RijndaelManaged rijndaelManaged = null;
            try
            {
                byte[] plainBytes = Encoding.UTF8.GetBytes(data);

                Byte[] byteKeys = new Byte[32];
                Array.Copy(Encoding.UTF8.GetBytes(key.PadRight(byteKeys.Length)), byteKeys, byteKeys.Length);

                string result = null;

                using (memoryStream = new MemoryStream())
                {
                    rijndaelManaged = new RijndaelManaged();
                    rijndaelManaged.Mode = mode;
                    rijndaelManaged.Padding = PaddingMode.PKCS7;
                    rijndaelManaged.KeySize = 128;
                    rijndaelManaged.Key = byteKeys;

                    using (cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(plainBytes, 0, plainBytes.Length);
                        cryptoStream.FlushFinalBlock();
                    }
                    result = Convert.ToBase64String(memoryStream.ToArray());
                }
                return result;
            }
            finally
            {
                if (cryptoStream != null) cryptoStream.Close();
                if (memoryStream != null) memoryStream.Close();
                if (rijndaelManaged != null) rijndaelManaged.Clear();
            }
        }

        /// <summary>
        /// AES 加密
        /// </summary>
        /// <param name="data">需要加密的数据</param>
        /// <param name="key">密钥</param>
        /// <param name="vector">向量</param>
        /// <returns></returns>
        public static string Encrypt(string data, string key, string vector)
        {
            MemoryStream memoryStream = null;
            CryptoStream cryptoStream = null;
            Rijndael rijndael = null;
            try
            {
                Byte[] plainBytes = Encoding.UTF8.GetBytes(data);

                Byte[] byteKeys = new Byte[32];
                Array.Copy(Encoding.UTF8.GetBytes(key.PadRight(byteKeys.Length)), byteKeys, byteKeys.Length);

                Byte[] byteVectors = new Byte[16];
                Array.Copy(Encoding.UTF8.GetBytes(vector.PadRight(byteVectors.Length)), byteVectors, byteVectors.Length);

                Byte[] cryptograph = null;

                rijndael = Rijndael.Create();
                using (memoryStream = new MemoryStream())
                {
                    using (cryptoStream = new CryptoStream(memoryStream, rijndael.CreateEncryptor(byteKeys, byteVectors), CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(plainBytes, 0, plainBytes.Length);
                        cryptoStream.FlushFinalBlock();

                        cryptograph = memoryStream.ToArray();
                    }
                }
                return Convert.ToBase64String(cryptograph);
            }
            finally
            {
                if (cryptoStream != null) cryptoStream.Close();
                if (memoryStream != null) memoryStream.Close();
                if (rijndael != null) rijndael.Clear();
            }
        }

        /// <summary>
        /// AES 解密
        /// </summary>
        /// <param name="data">需要解密的数据</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static string Decrypt(string data, string key, CipherMode mode = CipherMode.ECB)
        {
            MemoryStream memoryStream = null;
            CryptoStream cryptoStream = null;
            RijndaelManaged rijndaelManaged = null;
            try
            {
                Byte[] encryptedBytes = Convert.FromBase64String(data);

                Byte[] byteKeys = new Byte[32];
                Array.Copy(Encoding.UTF8.GetBytes(key.PadRight(byteKeys.Length)), byteKeys, byteKeys.Length);

                string result = null;
                using (memoryStream = new MemoryStream(encryptedBytes))
                {
                    rijndaelManaged = new RijndaelManaged();
                    rijndaelManaged.Mode = mode;
                    rijndaelManaged.Padding = PaddingMode.PKCS7;
                    rijndaelManaged.KeySize = 128;
                    rijndaelManaged.Key = byteKeys;

                    using (cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateDecryptor(), CryptoStreamMode.Read))
                    {
                        byte[] tmp = new byte[encryptedBytes.Length + 32];
                        int len = cryptoStream.Read(tmp, 0, encryptedBytes.Length + 32);
                        byte[] ret = new byte[len];
                        Array.Copy(tmp, 0, ret, 0, len);
                        result = Encoding.UTF8.GetString(ret);
                    }
                }
                return result;
            }
            catch
            {
                throw new Exception("解密失败，请检查key或加密是否使用向量");
            }
            finally
            {
                if (cryptoStream != null) cryptoStream.Close();
                if (memoryStream != null) memoryStream.Close();
                if (rijndaelManaged != null) rijndaelManaged.Clear();
            }
        }

        /// <summary>
        /// AES 解密
        /// </summary>
        /// <param name="data">需要解密的数据</param>
        /// <param name="key">密钥</param>
        /// <param name="vector">向量</param>
        /// <returns></returns>
        public static string Decrypt(string data, string key, string vector)
        {
            MemoryStream memoryStream = null;
            MemoryStream originalMemory = null;
            CryptoStream cryptoStream = null;
            Rijndael rijndael = null;
            try
            {
                Byte[] encryptedBytes = Convert.FromBase64String(data);

                Byte[] byteKeys = new Byte[32];
                Array.Copy(Encoding.UTF8.GetBytes(key.PadRight(byteKeys.Length)), byteKeys, byteKeys.Length);
                Byte[] byteVectors = new Byte[16];
                Array.Copy(Encoding.UTF8.GetBytes(vector.PadRight(byteVectors.Length)), byteVectors, byteVectors.Length);

                Byte[] original = null;

                rijndael = Rijndael.Create();
                using (memoryStream = new MemoryStream(encryptedBytes))
                {
                    using (cryptoStream = new CryptoStream(memoryStream, rijndael.CreateDecryptor(byteKeys, byteVectors), CryptoStreamMode.Read))
                    {
                        using (originalMemory = new MemoryStream())
                        {
                            Byte[] Buffer = new Byte[1024];
                            Int32 readBytes = 0;
                            while ((readBytes = cryptoStream.Read(Buffer, 0, Buffer.Length)) > 0)
                            {
                                originalMemory.Write(Buffer, 0, readBytes);
                            }
                            original = originalMemory.ToArray();
                        }
                    }
                }
                return Encoding.UTF8.GetString(original);
            }
            catch
            {
                throw new Exception("解密失败，请检查key或向量");
            }
            finally
            {
                if (originalMemory != null) originalMemory.Close();
                if (cryptoStream != null) cryptoStream.Close();
                if (memoryStream != null) memoryStream.Close();
                if (rijndael != null) rijndael.Clear();
            }
        }

    }
}
